# BSD3.0
# cili@163.com

import threading
import tkinter as tk
from tkinter import ttk, simpledialog, messagebox
import pickle
import re
import dnsserver


class MyDialog(simpledialog.Dialog):
    def __init__(self, parent, title, domain=None, ip_address=None):
        self.data = None
        self.selected_item = None
        self.initial_domain = domain
        self.initial_ip = ip_address
        self.tdata = title
        super().__init__(parent, title)

    def body(self, master):
        self.domain_label = tk.Label(master, text="域名:")
        self.domain_label.grid(row=0, column=0, padx=5, pady=5)
        self.domain_entry = tk.Entry(master)
        self.domain_entry.grid(row=0, column=1, padx=5, pady=5)

        if self.initial_domain:
            self.domain_entry.insert(0, self.initial_domain)

        self.ip_label = tk.Label(master, text="IP地址:")
        self.ip_label.grid(row=1, column=0, padx=5, pady=5)
        self.ip_entry = tk.Entry(master)
        self.ip_entry.grid(row=1, column=1, padx=5, pady=5)

        if self.initial_ip:
            self.ip_entry.insert(0, self.initial_ip)

        dstate = 'disable' if '删除' in self.tdata or '修改' in self.tdata else 'normal'
        istate = 'disable' if '删除' in self.tdata else 'normal'
        self.domain_entry.config(state=dstate)
        self.ip_entry.config(state=istate)

    def buttonbox(self):
        box = tk.Frame(self)
        confirm_button = tk.Button(box, text="确定", command=self.ok)
        confirm_button.pack(side="left", padx=5, pady=5)

        cancel_button = tk.Button(box, text="取消", command=self.cancel)
        cancel_button.pack(side="left", padx=5, pady=5)
        box.pack()

    def ok(self, event=None):
        self.data = (self.domain_entry.get(), self.ip_entry.get())
        super().ok()

    def cancel(self, event=None):
        super().cancel()


class DataEditor:
    def __init__(self, root):
        self.server = dnsserver.DNSServer(53)
        with open('data.bin', 'rb') as file:
            self.data = pickle.load(file)

        self.root = root
        self.root.title("DNS服务器")
        self.root.resizable(False, False)

        style = ttk.Style()
        style.theme_use('clam')
        style.configure("Treeview.Heading", font=("Helvetica", 9))
        style.configure("Treeview", font=("Helvetica", 9))

        self.top_panel = tk.Frame(root)
        self.top_panel.pack()
        self.title_label = tk.Label(self.top_panel, text='DNS服务器数据表', font=("Helvetica", 12, "bold"))
        self.title_label.pack(pady=10)
        self.tree = ttk.Treeview(self.top_panel, columns=("域名", "IP地址"), show="headings", style="Treeview")
        self.tree.heading("域名", text="域名")
        self.tree.heading("IP地址", text="IP地址")

        self.tree.pack(pady=5)
        for item in self.data:
            self.tree.insert("", "end", values=item)

        self.bottom_panel = tk.Frame(root)
        self.bottom_panel.pack()
        self.add_button = ttk.Button(self.bottom_panel, text="增加", command=self.add_data)
        self.add_button.pack(side="left", padx=5)
        self.delete_button = ttk.Button(self.bottom_panel, text="删除", command=self.delete_data)
        self.delete_button.pack(side="left", padx=5)
        self.modify_button = ttk.Button(self.bottom_panel, text="修改", command=self.modify_data)
        self.modify_button.pack(side="left", padx=5)

        self.status_panel = tk.Frame(root)
        self.status_panel.pack(fill="both", expand=True)
        self.status_label = tk.Label(self.status_panel, text='DNS服务未启动', font=("Helvetica", 10))
        self.status_label.pack(side="left", padx=5, pady=10)

        self.server = dnsserver.DNSServer(53)
        self.server.update(self.data)
        try:
            thread = threading.Thread(target=self.server.start)
            thread.daemon = True
            thread.start()
            self.status_label.config(text='DNS服务已启动', fg='green')
        except:
            self.status_label.config(text='DNS服务未启动', fg='red')
            messagebox.showinfo('提示', '启动失败！')

        self.root.update()
        # 获取窗口大小
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()

        # 计算居中位置
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        x = int((screen_width - window_width) / 2)
        y = int((screen_height - window_height) / 2)

        # 设置窗口位置
        self.root.geometry(f"+{x}+{y}")
        self.root.update()

    def add_data(self):
        record = MyDialog(self.root, '增加记录').data
        if record:
            if not self.is_valid_domain(record[0]) or not self.is_valid_ip(record[1]):
                messagebox.showinfo('提示', '输入的域名或IP地址不合法。')
                return
            exists = any(record[0] == item[0] for item in self.data)
            if exists:
                messagebox.showinfo('提示', '该记录已存在，增加无效。')
            else:
                self.data.append(record)
                self.tree.insert("", "end", values=record)
                self.save_data()

    def delete_data(self):
        selected_item = self.tree.selection()
        if selected_item:
            domain, ip_address = self.tree.item(selected_item, "values")
            record = MyDialog(self.root, '删除记录', domain=domain, ip_address=ip_address).data
            if record:
                self.tree.delete(selected_item)
                self.data.remove((domain, ip_address))
                self.save_data()
        else:
            messagebox.showinfo('提示', '请先选择一条数据。')

    def modify_data(self):
        selected_item = self.tree.selection()
        if selected_item:
            domain, ip_address = self.tree.item(selected_item, "values")
            record = MyDialog(self.root, '修改记录', domain=domain, ip_address=ip_address).data
            index = self.tree.index(selected_item)
            if record:
                exists = any(record[0] == item[0] for item in self.data)
                if exists and record[0] != domain:
                    messagebox.showinfo('提示', '该记录已存在，修改无效。')

                else:
                    self.tree.item(selected_item, values=record)
                    self.data[index] = record
                    self.save_data()
        else:
            messagebox.showinfo('提示', '请先选择一条数据。')

    def save_data(self):
        self.server.update(self.data)
        with open('data.bin', 'wb') as file:
            pickle.dump(self.data, file)

    def is_valid_domain(self, domain):
        domain_pattern = r"^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.(?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$"
        return bool(re.match(domain_pattern, domain))

    def is_valid_ip(self, ip):
        ip_pattern = r"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
        return bool(re.match(ip_pattern, ip))


if __name__ == "__main__":
    root = tk.Tk()
    editor = DataEditor(root)
    root.mainloop()
